/*
 * Copyright (c) 2006-2022, Ulandlink Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2022-12-12     xpw          first version
 */

#include <rtconfig.h>

#ifdef USING_PPP_DEVICE

#include <ppp_device.h>
#include <ppp_chat.h>
#include <rtdevice.h>
#include "drv_gpio.h"
#include <pin.h>

#define DBG_TAG    "ppp.w15"

#ifdef PPP_DEVICE_DEBUG
#define DBG_LVL   DBG_LOG
#else
#define DBG_LVL   DBG_INFO
#endif
#include <rtdbg.h>
#include <ppp_device_w15.h>
#include <ppp_utils_w15.h>
#include "app_sys_param.h"
#include "app_network_param.h"

#define DEBUG_CMD_ENABLE 1

#define W15_HOTSPOT_SSID_PREFIX         "EVC-"
#define W15_HOTSPOT_PWD_DEFAULT         ""
#define W15_HOTSPOT_IPV4_ADDR           "192.168.1.1"
#define W15_HOTSPOT_GATEWAY_ADDR        "192.168.1.1"

#define W15_POWER_PIN           GET_PIN(F,3)
#define W15_RESET_PIN           GET_PIN(F,2)
#define W15_RTS_PIN             GET_PIN(C, 2)
#define W15_CTS_PIN             GET_PIN(F, 10)
#define W15_POWER_ON            PIN_LOW
#define W15_POWER_OFF           PIN_HIGH
#define W15_WARTING_TIME_BASE   2000

static const struct modem_chat_data rst_mcd[] =
{
    {"+++",                         MODEM_CHAT_RESP_NOT_NEED,   30, 1, RT_TRUE},
};

static const struct modem_chat_data mcd[] =
{
    {"AT",                          MODEM_CHAT_RESP_NOT_NEED,   10, 1, RT_FALSE},
    {"AT",                          MODEM_CHAT_RESP_OK,         10, 1, RT_FALSE},
    {"ATE0",                        MODEM_CHAT_RESP_OK,         1,  1, RT_FALSE},

    /* config ppp mode */
    {"AT+UPPPC=101,172.30.0.252",   MODEM_CHAT_RESP_OK,         1,  1, RT_FALSE},
    {"AT+UPPPC=102,255.255.255.0",  MODEM_CHAT_RESP_OK,         1,  1, RT_FALSE},
    {"AT+UPPPC=107,1",              MODEM_CHAT_RESP_OK,         1,  1, RT_FALSE},
    {"AT+UPPPCA=1",                 MODEM_CHAT_RESP_OK,         1,  1, RT_FALSE},
     
    /* enter ppp mode */
    {"ATO3",                        MODEM_CHAT_RESP_OK,         1,  5, RT_FALSE},
};

static rt_err_t ppp_w15_prepare(struct ppp_device *device)
{
    if (device->power_pin >= 0)
    {
        rt_pin_write(device->power_pin, PIN_HIGH);
        rt_thread_mdelay(W15_WARTING_TIME_BASE / 20);
        rt_pin_write(device->power_pin, PIN_LOW);
        rt_thread_mdelay(W15_WARTING_TIME_BASE);
    }
    else
    {
        rt_err_t err;
        err = modem_chat(device->uart, rst_mcd, sizeof(rst_mcd) / sizeof(rst_mcd[0]));
        if (err)
            return err;
    }
    return modem_chat(device->uart, mcd, sizeof(mcd) / sizeof(mcd[0]));
}

/* ppp_w15_ops for ppp_device_ops , a common interface */
static struct ppp_device_ops w15_ops =
{
    .prepare = ppp_w15_prepare,
};

/**
 * register w15 into ppp_device
 *
 * @return  =0:   ppp_device register successfully
 *          <0:   ppp_device register failed
 */
int ppp_w15_register(void)
{
    struct ppp_device *ppp_device = RT_NULL;

    ppp_device = rt_malloc(sizeof(struct ppp_device));
    if(ppp_device == RT_NULL)
    {
        LOG_E("No memory for w15 ppp_device.");
        return -RT_ENOMEM;
    }

    ppp_device->power_pin = W15_POWER_PIN;
    ppp_device->reset_pin = W15_RESET_PIN;
    
    if (ppp_device->power_pin >= 0)
    {
        rt_pin_mode(ppp_device->power_pin, PIN_MODE_OUTPUT);
        rt_pin_write(ppp_device->power_pin, W15_POWER_ON);
        rt_thread_mdelay(W15_WARTING_TIME_BASE);
    }
    
    if (ppp_device->reset_pin >= 0)
    {
        rt_pin_mode(ppp_device->reset_pin, PIN_MODE_OUTPUT);
        rt_pin_write(ppp_device->reset_pin, PIN_LOW);
        rt_thread_mdelay(W15_WARTING_TIME_BASE);
    }
    
    /* pulldown cts and rts pin */
    rt_pin_mode(W15_RTS_PIN, PIN_MODE_OUTPUT);
	rt_pin_mode(W15_CTS_PIN, PIN_MODE_OUTPUT);
	rt_pin_write(W15_RTS_PIN, PIN_LOW);
	rt_pin_write(W15_CTS_PIN, PIN_LOW);
    
    ppp_device->ops = &w15_ops;

    LOG_D("ppp w15 is registering ppp_device");

    return ppp_device_register(ppp_device, PPP_DEVICE_NAME, RT_NULL, RT_NULL);
}
INIT_COMPONENT_EXPORT(ppp_w15_register);

rt_bool_t w15_wifi_enable(rt_bool_t is_enabled)
{
#define RETRY_TIMES 3
    
    int retry = 0;
    int result = RT_FALSE;
    char ssid[WIFI_PARAM_LEN + 1]= {0};
    char pwd[WIFI_PARAM_LEN + 1]= {0};
    
    while (1) { 
        if (is_enabled) {
            if (retry == 0) {
                app_network_param_get(NETWORK_WIFI_SSID, ssid, WIFI_PARAM_LEN);
                app_network_param_get(NETWORK_WIFI_PWD, pwd, WIFI_PARAM_LEN);
                
                LOG_I("load wifi ssid(%s), pwd(%s)", ssid, pwd);
            }
            
            /* deactivate wifi config */
            if (w15_exec_at_cmd(0, "AT+UWSCA=1,4") < 0) {
                goto __exit;
            }        
            /* set wifi ssid */
            if (w15_exec_at_cmd(0, "AT+UWSC=1,2,\"%s\"", ssid) < 0) {
                goto __exit;
            }
            if (strlen(pwd) >= 8) {
                /* set wifi security mode(WPA/WPA2/WPA3) */
                if (w15_exec_at_cmd(0, "AT+UWSC=1,5,2") < 0) {
                    goto __exit;
                }        
                /* set wifi pwd */
                if (w15_exec_at_cmd(0, "AT+UWSC=1,8,\"%s\"", pwd) < 0) {
                    goto __exit;
                }            
            } else {
                /* set wifi security mode(open) */
                if (w15_exec_at_cmd(0, "AT+UWSC=1,5,1") < 0) {
                    goto __exit;
                }            
            }
            /* activate wifi config */
            if (w15_exec_at_cmd(0, "AT+UWSCA=1,3") < 0) {
                goto __exit;
            }
            
            result = RT_TRUE;
            
        } else {
            /* deactivate wifi config */
            if (w15_exec_at_cmd(0, "AT+UWSCA=1,4") < 0) {
                goto __exit;
            }
            
            result = RT_TRUE;        
        }
    
__exit:
        
        if (!result) {
            retry ++;
            if (retry >= RETRY_TIMES) {
                break;
            }
            LOG_W("%s device w15 wifi failed, retry(%d)...", is_enabled ? "enable" : "disable", retry);
            continue;
        }
            
        break;
    }
    
    if (result) {
        LOG_I("device w15 wifi %s.", is_enabled ? "enabled" : "disabled");
    } else {
        LOG_E("%s device w15 wifi failed and no more retry. ", is_enabled ? "enable" : "disable");
    }
    
    return result;
}

rt_bool_t w15_hotspot_enable(rt_bool_t is_enabled)
{
#define RETRY_TIMES 3
    
    int retry = 0;
    char sn[128] = {0};
    char pwd[33] = {0};
    char sn_ssid[13] = {0};
    int result = RT_FALSE;
    
    while (1) {
        if (is_enabled) {
            app_sys_param_get(APP_SYS_PARAM_SN, sn, sizeof(sn));
            if (strlen(sn) <= 12) {
                rt_strncpy(sn_ssid, sn, strlen(sn));
            } else {
                rt_strncpy(sn_ssid, sn, 6);
                rt_strncpy(sn_ssid + 6, "-", 1);
                rt_strncpy(sn_ssid + 7, sn + strlen(sn) - 5, 5);
            }
            rt_strncpy(pwd, W15_HOTSPOT_PWD_DEFAULT, sizeof(pwd) - 1);
            
            /* deactivate hotspot config */
            if (w15_exec_at_cmd(0, "AT+UWAPCA=0,4") < 0) {
                goto __exit;
            }
            /* set hotspot ssid */
            if (w15_exec_at_cmd(0, "AT+UWAPC=0,2,\""W15_HOTSPOT_SSID_PREFIX"%s\"", sn_ssid) < 0) {
                goto __exit;
            }    
            /* set hotspot DHCP enable */
            if (w15_exec_at_cmd(0, "AT+UWAPC=0,106,1") < 0) {
                goto __exit;
            }
            /*  set hotspot ip address */
            if (w15_exec_at_cmd(0, "AT+UWAPC=0,101,"W15_HOTSPOT_IPV4_ADDR) < 0) {
                goto __exit;
            }
            /* set hotspot default gateway */
            if (w15_exec_at_cmd(0, "AT+UWAPC=0,103,"W15_HOTSPOT_GATEWAY_ADDR) < 0) {
                goto __exit;
            }
            if (strlen(pwd) >= 8) {
                /* set hotspot security mode(WPA/WPA2 mixed mode) */
                if (w15_exec_at_cmd(0, "AT+UWAPC=0,5,3,2") < 0) {
                    goto __exit;
                }
                /* set hotspot pwd */
                if (w15_exec_at_cmd(0, "AT+UWAPC=0,8,\"%s\"", pwd) < 0) {
                    goto __exit;
                }
            } else {
                /* set hotspot security mode(open) */
                if (w15_exec_at_cmd(0, "AT+UWAPC=0,5,1,1") < 0) {
                    goto __exit;
                }
            } 
            /* activate hotspot config */
            if (w15_exec_at_cmd(0, "AT+UWAPCA=0,3") < 0) {
                goto __exit;
            }           
            
            result = RT_TRUE;
            
        } else {
            /* deactivate hotspot config */
            if (w15_exec_at_cmd(0, "AT+UWAPCA=0,4") < 0) {
                goto __exit;
            }
            
            result = RT_TRUE;
        }
    
__exit:
        
        if (!result) {
            retry ++;
            if (retry >= RETRY_TIMES) {
                break;
            }
            LOG_W("%s device w15 hotspot failed, retry(%d)...", is_enabled ? "enable" : "disable", retry);
            continue;
        }
            
        break;
        
    }
    
    if (result) {
        if (is_enabled) {
            if (strlen(pwd) >= 8) {
                LOG_I("device w15 hotspot enabled(ssid:["W15_HOTSPOT_SSID_PREFIX"%s], pwd:[%s]).", sn_ssid, pwd);
            } else {
                LOG_I("device w15 hotspot enabled(ssid: "W15_HOTSPOT_SSID_PREFIX"%s).", sn_ssid);
            }
        } else {
            LOG_I("device w15 hotspot disabled.");
        }
    } else {
        LOG_E("%s device w15 hotspot failed and no more retry.", is_enabled ? "enable" : "disable");
    }
    
    return result;
}

/* these functions are for test w15 mudoule */
#if DEBUG_CMD_ENABLE
static int w15_control(int argc, char **argv)
{
    int result = RT_EOK;
    
    if (argc < 3) {
        rt_kprintf("Usage:\n");
        rt_kprintf("wifi <1/0>            - enable/disable wifi\n");
        rt_kprintf("hotspot <1/0>         - enable/disable hotspot\n");
        return -RT_ERROR;
    }
    
    if (!rt_strcmp(argv[1], "wifi")) {
        if (!rt_strcmp(argv[2], "1")) {
            result = w15_wifi_enable(RT_TRUE);
        } else if (!rt_strcmp(argv[2], "0")) {
            result = w15_wifi_enable(RT_FALSE);
        }
    } else if (!rt_strcmp(argv[1], "hotspot")) {
        if (!rt_strcmp(argv[2], "1")) {
            result = w15_hotspot_enable(RT_TRUE);
        } else if (!rt_strcmp(argv[2], "0")) {
            result = w15_hotspot_enable(RT_FALSE);
        }
    }
    
    return result;
}
MSH_CMD_EXPORT(w15_control, control device w15);
#endif
#endif
